package com.chenl.provider.DEMOS.Stream;

import java.util.*;
import java.util.stream.Collectors;

public class Collect收集 {
    //collect，收集，可以说是内容最繁多、功能最丰富的部分了。从字面上去理解，就是把一个流收集起来，最终可以是收集成一个值也可以收集成一个新的集合。
    //  collect主要依赖java.util.stream.Collectors类内置的静态方法。
    public static void main(String[] args) {
        List<Integer> list2 = Arrays.asList(1, 6, 3, 4, 6, 7, 9, 6, 20);
        List<Integer> listNew = list2.stream().filter(x -> x % 2 == 0).collect(Collectors.toList());
        Set<Integer> set = list2.stream().filter(x -> x % 2 == 0).collect(Collectors.toSet());

        List<Person> personList = new ArrayList<Person>();
        personList.add(new Person("Tom", 8900, 23, "male", "New York"));
        personList.add(new Person("Jack", 7000, 25, "male", "Washington"));
        personList.add(new Person("Lily", 7800, 21, "female", "Washington"));
        personList.add(new Person("Anni", 8200, 24, "female", "New York"));

        Map<?, Person> map = personList.stream().filter(p -> p.getSalary() > 8000)
                .collect(Collectors.toMap(Person::getName, p -> p,(v1,v2)->v2));//key为name,value为对象本身(不能为空,为空就空指针),若key重复,就永远取最新的
        System.out.println("toList:" + listNew);
        System.out.println("toSet:" + set);
        System.out.println("toMap:" + map);
    }

    //归集(toList/toSet/toMap)
        void toMethod(){
            List<Integer> list2 = Arrays.asList(1, 6, 3, 4, 6, 7, 9, 6, 20);
            List<Integer> listNew = list2.stream().filter(x -> x % 2 == 0).collect(Collectors.toList());
            Set<Integer> set = list2.stream().filter(x -> x % 2 == 0).collect(Collectors.toSet());

            List<Person> personList = new ArrayList<Person>();
            personList.add(new Person("Tom", 8900, 23, "male", "New York"));
            personList.add(new Person("Jack", 7000, 25, "male", "Washington"));
            personList.add(new Person("Lily", 7800, 21, "female", "Washington"));
            personList.add(new Person("Anni", 8200, 24, "female", "New York"));

            Map<?, Person> map = personList.stream().filter(p -> p.getSalary() > 8000)
                    .collect(Collectors.toMap(Person::getName, p -> p,(v1,v2)->v2));//key为name,value为对象本身(不能为空,为空就空指针),若key重复,就永远取最新的
            System.out.println("toList:" + listNew);
            System.out.println("toSet:" + set);
            System.out.println("toMap:" + map);
        }

    //统计(count/averaging)
    /*
    * 计数：count()
      平均值：averagingInt()、averagingLong()、averagingDouble()
      最值：maxBy()、minBy()
      求和：summingInt()、summingLong()、summingDouble()
      统计以上所有：summarizingInt()、summarizingLong()、summarizingDouble()
    * */
    void countMethod(){
        //统计员工人数、平均工资、工资总额、最高工资。
        List<Person> personList = new ArrayList<Person>();
        personList.add(new Person("Tom", 8900, 23, "male", "New York"));
        personList.add(new Person("Jack", 7000, 25, "male", "Washington"));
        personList.add(new Person("Lily", 7800, 21, "female", "Washington"));

        // 求总数
        Long count = personList.stream().collect(Collectors.counting());
        // 求平均工资
        Double average = personList.stream().collect(Collectors.averagingDouble(Person::getSalary));
        // 求最高工资
        Optional<Integer> max = personList.stream().map(Person::getSalary).collect(Collectors.maxBy(Integer::compare));
        // 求工资之和
        Integer sum = personList.stream().collect(Collectors.summingInt(Person::getSalary));
        // 一次性统计所有信息
        DoubleSummaryStatistics collect = personList.stream().collect(Collectors.summarizingDouble(Person::getSalary));

        System.out.println("员工总数：" + count);
        System.out.println("员工平均工资：" + average);
        System.out.println("员工工资总和：" + sum);
        System.out.println("员工工资所有统计：" + collect);
    }

    // 分组 partitioningBy()/groupingBy()
        //分区：将stream按条件分为两个Map，比如员工按薪资是否高于8000分为两部分。
        //分组：将集合分为多个Map，比如员工按性别分组。有单级分组和多级分组。
    void  groupMethod(){
        List<Person> personList = new ArrayList<Person>();
        personList.add(new Person("Tom", 8900,22, "male", "New York"));
        personList.add(new Person("Jack", 7000,22, "male", "Washington"));
        personList.add(new Person("Lily", 7800,22, "female", "Washington"));
        personList.add(new Person("Anni", 8200,22, "female", "New York"));
        personList.add(new Person("Owen", 9500,22, "male", "New York"));
        personList.add(new Person("Alisa", 7900,22, "female", "New York"));

        // 将员工按薪资是否高于8000分组
        Map<Boolean, List<Person>> part = personList.stream().collect(Collectors.partitioningBy(x -> x.getSalary() > 8000));
        // 将员工按性别分组
        Map<String, List<Person>> group = personList.stream().collect(Collectors.groupingBy(Person::getSex));
        // 将员工先按性别分组，再按地区分组
        Map<String, Map<String, List<Person>>> group2 = personList.stream().collect(Collectors.groupingBy(Person::getSex, Collectors.groupingBy(Person::getArea)));
        System.out.println("员工按薪资是否大于8000分组情况：" + part);
        System.out.println("员工按性别分组情况：" + group);
        System.out.println("员工按性别、地区：" + group2);
    }

    //接合(joining)
        //joining可以将stream中的元素用特定的连接符（没有的话，则直接连接）连接成一个字符串。
    void joinMethod(){
        List<Person> personList = new ArrayList<Person>();
        personList.add(new Person("Tom", 8900, 23, "male", "New York"));
        personList.add(new Person("Jack", 7000, 25, "male", "Washington"));
        personList.add(new Person("Lily", 7800, 21, "female", "Washington"));

        String names = personList.stream().map(p -> p.getName()).collect(Collectors.joining(","));
        System.out.println("所有员工的姓名：" + names);
        List<String> list = Arrays.asList("A", "B", "C");
        String string = list.stream().collect(Collectors.joining("-"));
        System.out.println("拼接后的字符串：" + string);
    }

    // 归约(reducing)
        //Collectors类提供的reducing方法，相比于stream本身的reduce方法，增加了对自定义归约的支持。
    void reducMethod(){
        List<Person> personList = new ArrayList<Person>();
        personList.add(new Person("Tom", 8900, 23, "male", "New York"));
        personList.add(new Person("Jack", 7000, 25, "male", "Washington"));
        personList.add(new Person("Lily", 7800, 21, "female", "Washington"));

        // 每个员工减去起征点后的薪资之和（这个例子并不严谨，但一时没想到好的例子）
        Integer sum = personList.stream().collect(Collectors.reducing(0, Person::getSalary, (i, j) -> (i + j - 5000)));
        System.out.println("员工扣税薪资总和：" + sum);

        // stream的reduce
        Optional<Integer> sum2 = personList.stream().map(Person::getSalary).reduce(Integer::sum);
        System.out.println("员工薪资总和：" + sum2.get());
    }



}
